home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / COMMON.ZIP / GIF.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-27  |  21.5 KB  |  758 lines

  1. /*
  2.  
  3.   AJR
  4.  
  5.   I have found many example of GIF decoders, but this is the only one
  6.   that worked. Steve Rimmer's otherwise excelent book (Supercharged
  7.   Bitmapped Graphics) has a giff decoder, but it didn't work
  8.   (for me anyways - maybe I made a typeo :( ).
  9.  
  10.   Anyways here is code, by Steven A. Bennet that works.
  11.   Now remember Unisys is now charging royalties for all
  12.   commercial use of the gif format!!!!
  13.  
  14.   This file has two file, a C file, followed by an H file.
  15.   the C file has a bit of code specific to the project I was using
  16.   the code for, but it should be easy to remove/replace with your
  17.   own routines.
  18.  
  19.  
  20.   tested on 640x400 256 colour images.
  21.  
  22. */
  23.  
  24.  
  25. /*
  26.  
  27.     giff.c
  28.  
  29.     unpackgiffblock()Copyright (C) 1987, by Steven A. Bennett
  30.  
  31.     Modified by AJR june 1994 to work with personal lib.
  32.     Note! this code contains references to stuff in AJR's
  33.     private libs, but all of this stuff is easily replaced with
  34.     your own code.
  35.  
  36.     memalloc() - replace with farmalloc()
  37.     memfree()  - replace with farfree()
  38.     pr2()      - debug code, print to second monitor
  39.     g_get_byte() - gets the next byte from the file,
  40.                    if you want SLOW code just use fread()
  41.                    otherwise write some buffering code.
  42.     g_read_bytes() - next x bytes, see above comment
  43.     g_skip_bytes() - skip next x bytes (fseek() sortof)
  44.     other stuff noted in the code.
  45.  
  46.     All comments by Steven, unless otherwise noted.
  47.  
  48.     AJR
  49.     Created - 1994//6//22
  50.  
  51.     History:
  52.         New file
  53.  
  54. */
  55.  
  56. // AJR not ALL of these include are required, I am just lazy
  57. // and include everything.
  58.  
  59. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <alloc.h>
  62. #include <dos.h>
  63. #include <string.h>
  64. #include <time.h>
  65. #include <conio.h>
  66. #include <ctype.h>
  67. #include <dir.h>
  68. #include <bios.h>
  69. #include <process.h>
  70. #include <io.h>
  71.  
  72.  
  73. #include "giff.h"
  74.  
  75. // AJR bunch of project specific includes snippped here
  76.  
  77.  
  78. BITMAP far *giff_shape;  // AJR used by my draw code
  79. short giff_x, giff_y;    // AJR ditto
  80.  
  81. // AJR - code to skip weird blocks
  82. /* ---------------------- skip_ext() ---------------------- June 22,1994 */
  83. short skip_ext(g_file_t *gf)
  84. {
  85.    plaintext_t pt;
  86.    controlblock_t cb;
  87.    application_t ap;
  88.    unsigned char c, n;
  89.  
  90.    c=g_get_byte(gf);
  91.    switch ( c )
  92.       {
  93.       case 0x01: // plain text descriptor
  94. //pr2("got plain text block");
  95.          g_read_bytes((char far *)&pt, sizeof(pt), gf);
  96.          n=g_get_byte(gf);
  97.          // skip text
  98.          g_skip_bytes(n, gf);
  99.          break;
  100.  
  101.       case 0xf9:  // graphic control block
  102. //pr2("control block");
  103. //pr2("sizeof cb = %d (6)", sizeof(cb));
  104.          g_read_bytes((char far *)&cb, sizeof(cb), gf);
  105.          break;
  106.  
  107.       case 0xfe: // comment block
  108. //pr2("comment block");
  109.          n=g_get_byte(gf);
  110.          // skip comment
  111.          g_skip_bytes(n, gf);
  112.          break;
  113.  
  114.       case 0xff: // application ext
  115. //pr2("application block");
  116.          g_read_bytes((char far *)&ap, sizeof(cb), gf);
  117.          n=g_get_byte(gf);
  118.          // skip data
  119.          g_skip_bytes(n, gf);
  120.          break;
  121.  
  122.       default:
  123. //pr2("unknown extension %d skipped", c);
  124.          n=g_get_byte(gf);
  125.          // skip data
  126.          g_skip_bytes(n, gf);
  127.          break;
  128.       }
  129.  
  130.    return(FALSE);
  131. }
  132.  
  133.  
  134. /* DECODE.C - An LZW decoder for GIF
  135.  * Copyright (C) 1987, by Steven A. Bennett
  136.  *
  137.  * Permission is given by the author to freely redistribute and include
  138.  * this code in any program as long as this credit is given where due.
  139.  *
  140.  * In accordance with the above, I want to credit Steve Wilhite who wrote
  141.  * the code which this is heavily inspired by...
  142.  *
  143.  * GIF and 'Graphics Interchange Format' are trademarks (tm) of
  144.  * Compuserve, Incorporated, an H&R Block Company.
  145.  *
  146.  * Release Notes: This file contains a decoder routine for GIF images
  147.  * which is similar, structurally, to the original routine by Steve Wilhite.
  148.  * It is, however, somewhat noticably faster in most cases.
  149.  *
  150.  */
  151.  
  152.  
  153. #if 0
  154. /*  short get_byte()
  155.  *
  156.  *   - This external (machine specific) function is expected to return
  157.  * either the next byte from the GIF file, or a negative number, as
  158.  * defined in ERRS.H.
  159.  */
  160.  short get_byte();
  161.  
  162. /*  short out_line(pixels, linelen)
  163.  *     UBYTE pixels[];
  164.  *     short linelen;
  165.  *
  166.  *   - This function takes a full line of pixels (one byte per pixel) and
  167.  * displays them (or does whatever your program wants with them...).  It
  168.  * should return zero, or negative if an error or some other event occurs
  169.  * which would require aborting the decode process...  Note that the length
  170.  * passed will almost always be equal to the line length passed to the
  171.  * decoder function, with the sole exception occurring when an ending code
  172.  * occurs in an odd place in the GIF file...  In any case, linelen will be
  173.  * equal to the number of pixels passed...
  174.  */
  175.  short out_line();
  176.  
  177. /*  short bad_code_count;
  178.  *
  179.  * This value is the only other global required by the using program, and
  180.  * is incremented each time an out of range code is read by the decoder.
  181.  * When this value is non-zero after a decode, your GIF file is probably
  182.  * corrupt in some way...
  183.  */
  184. #endif
  185.  
  186.  
  187. // AJR - this draws one complete decoded line of graphic
  188. // you can alter this routine to draw, store whatever you like.
  189. /* ---------------------- out_line() ---------------------- June 27,1994 */
  190. short out_line(unsigned char far *pixels, short width)
  191. {
  192.    _fmemcpy(&giff_shape->data,pixels, width);
  193.    drawshape(giff_x, giff_y, giff_shape);
  194.    giff_y++;
  195.  
  196.    return 0;
  197. }
  198.  
  199.  
  200. short bad_code_count;
  201.  
  202. #define MAX_CODES   4095
  203.  
  204. /* Static variables */
  205. static short curr_size;                     /* The current code size */
  206. static short clear;                         /* Value for a clear code */
  207. static short ending;                        /* Value for a ending code */
  208. static short newcodes;                      /* First available code */
  209. static short top_slot;                      /* Highest code for current size */
  210. static short slot;                          /* Last read code */
  211.  
  212. /* The following static variables are used
  213.  * for seperating out codes
  214.  */
  215. static short navail_bytes = 0;              /* # bytes left in block */
  216. static short nbits_left = 0;                /* # bits left in current byte */
  217. static unsigned char b1;                           /* Current byte */
  218. static unsigned char byte_buff[257];               /* Current block */
  219. static unsigned char *pbytes;                      /* Pointer to next byte in block */
  220.  
  221. static LONG code_mask[13] = {
  222.      0,
  223.      0x0001, 0x0003,
  224.      0x0007, 0x000F,
  225.      0x001F, 0x003F,
  226.      0x007F, 0x00FF,
  227.      0x01FF, 0x03FF,
  228.      0x07FF, 0x0FFF
  229.      };
  230.  
  231. /* get_next_code()
  232.  * - gets the next code from the GIF file.  Returns the code, or else
  233.  * a negative number in case of file errors...
  234.  */
  235. static short get_next_code(g_file_t *gf)
  236.    {
  237.    short i, x;
  238.    unsigned long ret;
  239.  
  240.    if (nbits_left == 0)
  241.       {
  242.       if (navail_bytes <= 0)
  243.          {
  244.  
  245.          /* Out of bytes in current block, so read next block
  246.           */
  247.          pbytes = byte_buff;
  248.          if ((navail_bytes = g_get_byte(gf)) < 0)
  249.             return(navail_bytes);
  250.          else if (navail_bytes)
  251.             {
  252.             for (i = 0; i < navail_bytes; ++i)
  253.                {
  254.                if ((x = g_get_byte(gf)) < 0)
  255.                   return(x);
  256.                byte_buff[i] = x;
  257.                }
  258.             }
  259.          }
  260.       b1 = *pbytes++;
  261.       nbits_left = 8;
  262.       --navail_bytes;
  263.       }
  264.  
  265.    ret = b1 >> (8 - nbits_left);
  266.    while (curr_size > nbits_left)
  267.       {
  268.       if (navail_bytes <= 0)
  269.          {
  270.  
  271.          /* Out of bytes in current block, so read next block
  272.           */
  273.          pbytes = byte_buff;
  274.          if ((navail_bytes = g_get_byte(gf)) < 0)
  275.             return(navail_bytes);
  276.          else if (navail_bytes)
  277.             {
  278.             for (i = 0; i < navail_bytes; ++i)
  279.                {
  280.                if ((x = g_get_byte(gf)) < 0)
  281.                   return(x);
  282.                byte_buff[i] = x;
  283.                }
  284.             }
  285.          }
  286.       b1 = *pbytes++;
  287.       ret |= b1 << nbits_left;
  288.       nbits_left += 8;
  289.       --navail_bytes;
  290.       }
  291.    nbits_left -= curr_size;
  292.    ret &= code_mask[curr_size];
  293.    return((short)(ret));
  294.    }
  295.  
  296.  
  297. /* The reason we have these seperated like this instead of using
  298.  * a structure like the original Wilhite code did, is because this
  299.  * stuff generally produces significantly faster code when compiled...
  300.  * This code is full of similar speedups...  (For a good book on writing
  301.  * C for speed or for space optomisation, see Efficient C by Tom Plum,
  302.  * published by Plum-Hall Associates...)
  303.  */
  304.  
  305. static unsigned char far *stack;      /* Stack for storing pixels */
  306. static unsigned char far *suffix;     /* Suffix table */
  307. static unsigned short far *prefix;    /* Prefix linked list */
  308.  
  309. /* short decoder(linewidth)
  310.  *    short linewidth;               * Pixels per line of image *
  311.  *
  312.  * - This function decodes an LZW image, according to the method used
  313.  * in the GIF spec.  Every *linewidth* "characters" (ie. pixels) decoded
  314.  * will generate a call to out_line(), which is a user specific function
  315.  * to display a line of pixels.  The function gets it's codes from
  316.  * get_next_code() which is responsible for reading blocks of data and
  317.  * seperating them into the proper size codes.  Finally, get_byte() is
  318.  * the global routine to read the next byte from the GIF file.
  319.  *
  320.  * It is generally a good idea to have linewidth correspond to the actual
  321.  * width of a line (as specified in the Image header) to make your own
  322.  * code a bit simpler, but it isn't absolutely necessary.
  323.  *
  324.  * Returns: 0 if successful, else negative.  (See ERRS.H)
  325.  *
  326.  */
  327.  
  328. short unpackgiffblock(short linewidth, g_file_t *gf, short dx, short dy)
  329.    {
  330.    unsigned char *bufptr;
  331.    unsigned char far *sp;
  332.    unsigned char *buf;
  333.    short code, fc, oc, bufcnt;
  334.    short c, size, ret;
  335.  
  336.     giff_shape=allocwindow(linewidth, 1,1,1,0); // AJR - init draw code
  337.    if ( giff_shape )
  338.       {
  339.       giff_x=dx;
  340.       giff_y=dy;
  341.  
  342.       /* Initialize for decoding a new image...
  343.       */
  344.       size=g_get_byte(gf);
  345.       if (size < 2 || 9 < size )
  346.          return(BAD_CODE_SIZE);
  347.    
  348.  
  349.       stack=memalloc(MAX_CODES +1);           /* Stack for storing pixels */
  350.       suffix=memalloc(MAX_CODES + 1);         /* Suffix table */
  351.       prefix=memalloc((MAX_CODES + 1)*sizeof(short));    /* Prefix linked list */
  352.  
  353.       if ( prefix == NULL )
  354.          {
  355.          if ( suffix )
  356.             memfree(suffix);
  357.          if ( stack )
  358.             memfree(stack);
  359.          pr2("out of mem");
  360.          return OUT_OF_MEMORY;
  361.          }
  362.  
  363.       curr_size = size + 1;
  364.       top_slot = 1 << curr_size;
  365.       clear = 1 << size;
  366.       ending = clear + 1;
  367.       slot = newcodes = ending + 1;
  368.       navail_bytes = nbits_left = 0;
  369.       bad_code_count=0;
  370.  
  371.       /* Initialize in case they forgot to put in a clear code.
  372.       * (This shouldn't happen, but we'll try and decode it anyway...)
  373.       */
  374.       oc = fc = 0;
  375.  
  376.       /* Allocate space for the decode buffer
  377.       */
  378.       if ((buf = (unsigned char *)malloc(linewidth + 1)) == NULL)
  379.          {
  380.          pr2("out of mem 2");
  381.          return(OUT_OF_MEMORY);
  382.          }
  383.  
  384.       /* Set up the stack pointer and decode buffer pointer
  385.       */
  386.       sp = stack;
  387.       bufptr = buf;
  388.       bufcnt = linewidth;
  389.  
  390.       /* This is the main loop.  For each code we get we pass through the
  391.       * linked list of prefix codes, pushing the corresponding "character" for
  392.       * each code onto the stack.  When the list reaches a single "character"
  393.       * we push that on the stack too, and then start unstacking each
  394.       * character for output in the correct order.  Special handling is
  395.       * included for the clear code, and the whole thing ends when we get
  396.       * an ending code.
  397.       */
  398.       while ((c = get_next_code(gf)) != ending )
  399.          {
  400.  
  401.          /* If we had a file error, return without completing the decode
  402.          */
  403.          if (c < 0)
  404.             {
  405.             free(buf);
  406.             return(0);
  407.             }
  408.  
  409.          /* If the code is a clear code, reinitialize all necessary items.
  410.          */
  411.          if ( c == clear )
  412.             {
  413.             curr_size = size + 1;
  414.             slot = newcodes;
  415.             top_slot = 1 << curr_size;
  416.  
  417.             /* Continue reading codes until we get a non-clear code
  418.             * (Another unlikely, but possible case...)
  419.             */
  420.             while ((c = get_next_code(gf)) == clear)
  421.                ;
  422.  
  423.             /* If we get an ending code immediately after a clear code
  424.             * (Yet another unlikely case), then break out of the loop.
  425.             */
  426.             if (c == ending)
  427.                break;
  428.  
  429.             /* Finally, if the code is beyond the range of already set codes,
  430.             * (This one had better NOT happen...  I have no idea what will
  431.             * result from this, but I doubt it will look good...) then set it
  432.             * to color zero.
  433.             */
  434.             if (c >= slot)
  435.                c = 0;
  436.  
  437.             oc = fc = c;
  438.  
  439.             /* And let us not forget to put the char into the buffer... And
  440.             * if, on the off chance, we were exactly one pixel from the end
  441.             * of the line, we have to send the buffer to the out_line()
  442.             * routine...
  443.             */
  444.             *bufptr++ = c;
  445.             if (--bufcnt == 0)
  446.                {
  447.                if ((ret = out_line((char far *)buf, linewidth)) < 0)
  448.                   {
  449.                   free(buf);
  450.                   return(ret);
  451.                   }
  452.                bufptr = buf;
  453.                bufcnt = linewidth;
  454.                }
  455.             }
  456.          else
  457.             {
  458.  
  459.             /* In this case, it's not a clear code or an ending code, so
  460.             * it must be a code code...  So we can now decode the code into
  461.             * a stack of character codes. (Clear as mud, right?)
  462.             */
  463.             code = c;
  464.  
  465.             /* Here we go again with one of those off chances...  If, on the
  466.             * off chance, the code we got is beyond the range of those already
  467.             * set up (Another thing which had better NOT happen...) we trick
  468.             * the decoder into thinking it actually got the last code read.
  469.             * (Hmmn... I'm not sure why this works...  But it does...)
  470.             */
  471.             if (code >= slot)
  472.                {
  473.                if (code > slot)
  474.                   ++bad_code_count;
  475.                code = oc;
  476.                *sp++ = fc;
  477.                }
  478.  
  479.             /* Here we scan back along the linked list of prefixes, pushing
  480.             * helpless characters (ie. suffixes) onto the stack as we do so.
  481.             */
  482.             while (code >= newcodes)
  483.                {
  484.                *sp++ = suffix[code];
  485.                code = prefix[code];
  486.                }
  487.  
  488.             /* Push the last character on the stack, and set up the new
  489.             * prefix and suffix, and if the required slot number is greater
  490.             * than that allowed by the current bit size, increase the bit
  491.             * size.  (NOTE - If we are all full, we *don't* save the new
  492.             * suffix and prefix...  I'm not certain if this is correct...
  493.             * it might be more proper to overwrite the last code...
  494.             */
  495.             *sp++ = code;
  496.             if (slot < top_slot)
  497.                {
  498.                suffix[slot] = fc = code;
  499.                prefix[slot++] = oc;
  500.                oc = c;
  501.                }
  502.             if (slot >= top_slot)
  503.                if (curr_size < 12)
  504.                   {
  505.                   top_slot <<= 1;
  506.                   ++curr_size;
  507.                   } 
  508.  
  509.             /* Now that we've pushed the decoded string (in reverse order)
  510.             * onto the stack, lets pop it off and put it into our decode
  511.             * buffer...  And when the decode buffer is full, write another
  512.             * line...
  513.             */
  514.             while (sp > stack)
  515.                {
  516.                *bufptr++ = *(--sp);
  517.                if (--bufcnt == 0)
  518.                   {
  519.                   if ((ret = out_line((char far *)buf, linewidth)) < 0)
  520.                      {
  521.                      free(buf);
  522.                      return(ret);
  523.                      }
  524.                   bufptr = buf;
  525.                   bufcnt = linewidth;
  526.                   }
  527.                }
  528.             }
  529.          }
  530.  
  531.       ret = 0;
  532.       if (bufcnt != linewidth)
  533.          ret = out_line((char far *)buf, (linewidth - bufcnt));
  534.  
  535.       memfree(buf);
  536.       memfree(prefix);
  537.       memfree(suffix);
  538.       memfree(stack);
  539.  
  540.       freewindow(giff_shape); // AJR - deinit draw stuff
  541.       }
  542.  
  543.    return(ret);
  544.    }
  545.  
  546.  
  547.  
  548. // AJR - wrapper for unpack
  549. /* ---------------------- unpack_giff() ------------------- June 22,1994 */
  550. short unpack_giff(g_file_t *gf, unsigned short flags, short x, short y)
  551. {
  552.    gifheader_t gh;
  553.    imageblock_t iblk;
  554.    fileinfo_t fi;
  555.    long t;
  556.    short b, c, done, i;
  557.    unsigned char *p;
  558.  
  559.    // make sure gif file
  560.    g_read_bytes((char far *)&gh, sizeof(gh) - 1, gf);
  561.    if ( memcmp(gh.sig, "GIF", 3) )
  562.       {
  563.       pr2("NOT a gif file");
  564.       return 1;
  565.       }
  566.  
  567.    fi.width=gh.screenwidth;
  568.    fi.depth=gh.screendepth;
  569.    fi.bits=gh.flags & 0x07;
  570.    fi.bits++;
  571.    fi.background=gh.background;
  572.    
  573.    // get color map if there is one
  574.    if ( gh.flags & 0x80 )
  575.       {
  576.       c=3 * (1<<((gh.flags & 7 ) + 1));
  577.       g_read_bytes((char far *)fi.palette, c, gf);
  578.       if ( flags & USE_PALETTE )
  579.          {
  580.          // AJR - vga only uses 6 bits
  581.          for ( p=fi.palette, i=0; i < 768; i++, p++ )
  582.             *p>>=2;
  583.          setvgapalette(fi.palette);
  584.          }
  585.       }
  586.  
  587.    // step thru blocks
  588.    done=0;
  589.    while ( !done )
  590.       {
  591.       c=g_get_byte(gf);
  592.  
  593.       switch ( c )
  594.          {
  595.          case ',': // image block
  596.             g_read_bytes((char far *)&iblk, sizeof(iblk) - 1, gf);
  597.             fi.width=iblk.width;
  598.             fi.depth=iblk.depth;
  599. //pr2("image block width %d height %d",fi.width, fi.depth);
  600.  
  601.             // local color map
  602.             if ( iblk.flags & 0x80 )
  603.                {
  604. //pr2("local color map");
  605.                b= 3 * (1<<((iblk.flags & 0x07) + 1));
  606.                g_read_bytes((char far *)&fi.palette, b, gf);
  607.                fi.bits=iblk.flags & 0x07;
  608.                fi.bits++;
  609.                }
  610.  
  611.             fi.flags=iblk.flags;
  612.  
  613.             t=unpackgiffblock(fi.width, gf, x, y);
  614. //pr2("bad code count = %d", bad_code_count);
  615.             if ( t )
  616.                {
  617. //pr2("ERROR unpacking gif");
  618.                done=1;
  619.                //return 3;
  620.                }
  621.             break;
  622.  
  623.          case '!': // ext block
  624. //pr2("ext block");
  625.             skip_ext(gf);
  626.             break;
  627.  
  628.          case ';':
  629.          case 0:
  630.             // all done
  631. //pr2("all done c = %d %c", c, c);
  632.             done=1;
  633.             break;
  634.  
  635.          default:
  636. //pr2("unkhown block type %c %d", c,c);
  637.             //return 2;
  638.             done=1;               
  639.             break;
  640.          }
  641.  
  642.       }
  643.  
  644.    return(0);
  645. }
  646.  
  647.  
  648.  
  649. // AJR - ignores palette info in the picture, unless flags says otherwiae
  650. /* ---------------------- show_local_giff() ------------------ May 1,1994 */
  651. void show_local_giff(char *fname, short x, short y, unsigned short flags)
  652. {
  653.    g_file_t *gf;
  654.  
  655.    // AJR - open and buffer file so we can do fast single byte reads
  656.    gf=gopen_resource(fname, flags);
  657.     if ( gf )
  658.        {
  659.        if ( unpack_giff(gf, flags, x, y) )
  660.          {
  661.          pr2("Error unpacking %s", fname);
  662.          }
  663.        }
  664.    else
  665.       {
  666.       pr2("Error loading gif %s", fname);
  667.       }
  668.  
  669. }
  670.  
  671.  
  672. /* ------------------------------ EOF -------------------------------- */
  673.  
  674. /* ---------------------------------------------------------------- */
  675. /* ---------------------------------------------------------------- */
  676. /* ---------------------------------------------------------------- */
  677. /* ------------ the include file ---------------------------------- */
  678. /* ---------------------------------------------------------------- */
  679. /* ---------------------------------------------------------------- */
  680. /* ---------------------------------------------------------------- */
  681.  
  682. /*
  683.  
  684.     giff.h
  685.  
  686.     Copyright 1994, June 22 by Alec Russell, ALL rights reserved
  687.  
  688.     Created - 1994//6//22
  689.  
  690.     History:
  691.         New file
  692.  
  693. */
  694.  
  695. #define OUT_OF_MEMORY -10
  696. #define BAD_CODE_SIZE -20
  697. #define READ_ERROR -1
  698. #define WRITE_ERROR -2
  699. #define OPEN_ERROR -3
  700. #define CREATE_ERROR -4
  701.  
  702. typedef struct
  703.    {
  704.    char sig[6];
  705.    unsigned int screenwidth, screendepth;
  706.    unsigned char flags, background, aspect;
  707.    }
  708. gifheader_t;
  709.  
  710. typedef struct
  711.    {
  712.    unsigned int left, top, width, depth;
  713.    unsigned char flags;
  714.    }
  715. imageblock_t;
  716.  
  717. typedef struct
  718.    {
  719.    int width, depth, bits;
  720.    unsigned int flags;
  721.    int background;
  722.    unsigned char palette[768];
  723.    }
  724. fileinfo_t;
  725.  
  726. typedef struct
  727.    {
  728.    unsigned char blocksize;
  729.    unsigned char flags;
  730.    unsigned int delay;
  731.    unsigned char transparent_color;
  732.    unsigned char terminator;
  733.    }
  734. controlblock_t;
  735.  
  736. typedef struct
  737.    {
  738.    unsigned char blocksize;
  739.    char applstring[8];
  740.    unsigned char authentication[3];
  741.    }
  742. application_t;
  743.  
  744. typedef struct
  745.    {
  746.    unsigned char blocksize;
  747.    unsigned int left, top, gridwith, gridheight;
  748.    unsigned char cellwidth, cellheight;
  749.    unsigned char forecolor, backcolor;
  750.    }
  751. plaintext_t;
  752.  
  753.  
  754. /* ------------------------------ EOF -------------------------------- */
  755.  
  756.  
  757.  
  758.